using System;
using System.Collections.Generic;
using System.Text;
using CGraph.DirectedGraph;
using CGraph.DirectedGraph.Impl;
using CGraph.Generic.Impl;
using CGraph.Generic;
using CGraph.AppGraph;
using NUnit.Framework;
using Microsoft.FSharp.Core;

namespace CGraph_Tests
{
    [TestFixture]
    public class AppGraph_Test2
    {
        public class ProviderImpl : Impl.IProviderImpl
        {
            public delegate void InitTest(IServiceInit service);
            public delegate void PostInitTest(IServiceRecord record);
            InitTest m_initTest;
            PostInitTest m_postInitTest;
            string[] m_result;
            string m_name;
            public ProviderImpl(InitTest initTest, PostInitTest postInitTest, string[] result, string name)
            {
                m_result = result;
                m_name = name;
                m_initTest = initTest;
                m_postInitTest = postInitTest;
            }
            #region IProviderImpl Members

            public Tuple<string, object>[] Init(IServiceInit service)
            {
                m_initTest(service);
                service.AddInitHook(FuncConvert.ToFastFunc((Converter<IServiceRecord, Unit>)delegate(IServiceRecord record) { m_postInitTest(record); return new Unit(0); }));
                List<Tuple<string, object>> retval = new List<Tuple<string, object>>();
                foreach( string res in m_result )
                    retval.Add( new Tuple<string,object>( res, m_name ) );
                return retval.ToArray();
            }

            #endregion

            #region INamedObject Members

            public string Name
            {
                get { return m_name; }
            }

            #endregion
        }
        public static void AddProvider(Impl.IGraphBuilder builder, string name, string[] req
            , string[] opt, string[] provide, string[] result, string[] pinitest, string[] ninittest
            , string[] prectest, string[] nrectest )
        {
            builder.AddProviderImpl(new ProviderImpl(
                delegate(IServiceInit init)
                {
                    foreach (string p in pinitest)
                        Assert.IsTrue(init.ServiceCreated(p));
                    foreach (string n in ninittest)
                        Assert.IsFalse(init.ServiceCreated(n));
                }
                , delegate(IServiceRecord record)
                {
                    foreach (string p in prectest)
                        Assert.IsNotNull(record[p]);
                    foreach (string n in nrectest)
                        Assert.IsNull(record[n]);
                }, result, name)
                , req, opt, provide);
        }
        /// <summary>
        /// Test that the service init provider actually returns correct
        /// answers to a query.
        /// </summary>
        [Test]
        public void TestAppGraphInitQuery()
        {
            IAppGraph graph = new Impl.AppGraph();
            Impl.IGraphBuilder builder = new Impl.GraphBuilder(graph);
            AddProvider(builder, "a", new string[] { }, new string[] { }, new string[] { "aa", "ab" }, new string[] { "aa", "ab" },
                new string[] { }, new string[] { "aa", "ab", "ba", "bb", "cb" }, new string[] { }, new string[] { "aa", "ab", "ba", "bb", "cb" });

            AddProvider(builder, "b", new string[] { "aa", "ab" }, new string[] { }, new string[] { "ba", "bb" }, new string[] { "ba", "bb" },
                new string[] { "aa", "ab" }, new string[] { "ba", "bb", "cb" }, new string[] { "aa", "ab" }, new string[] { "ba", "bb", "cb" });

            AddProvider(builder, "c", new string[] { "aa", "bb" }, new string[] { }, new string[] { "aa", "cb" }, new string[] { "aa", "cb" },
                new string[] { "aa", "ab", "ba", "bb" }, new string[] { "cb" }, new string[] { "aa", "bb" }, new string[] { "ba", "ab", "cb" });

            Dictionary<string, object> services = Impl.InitializeGraph(graph, new Option<FastFunc<Tuple<IProviderVertex, IEnumerable<string>>, Unit>>());

            Assert.AreEqual("a", services["ab"]);
            Assert.AreEqual("b", services["ba"]);
            Assert.AreEqual("b", services["bb"]);
            Assert.AreEqual("c", services["aa"]);
            Assert.AreEqual("c", services["cb"]);
        }
        /// <summary>
        /// Set up same scenario, but register objects backwards and
        /// ensure their only dependencies are optional dependencies.
        /// </summary>
        [Test]
        public void TestOptionalOrder()
        {
            IAppGraph graph = new Impl.AppGraph();
            Impl.IGraphBuilder builder = new Impl.GraphBuilder(graph);

            AddProvider(builder, "c", new string[] { }, new string[] { "aa", "bb" }, new string[] { "aa", "cb" }, new string[] { "aa", "cb" },
                new string[] { "aa", "ab", "ba", "bb" }, new string[] { "cb" }, new string[] { "aa", "bb" }, new string[] { "ba", "ab", "cb" });

            AddProvider(builder, "b", new string[] { }, new string[] { "aa", "ab" }, new string[] { "ba", "bb" }, new string[] { "ba", "bb" },
                new string[] { "aa", "ab" }, new string[] { "ba", "bb", "cb" }, new string[] { "aa", "ab" }, new string[] { "ba", "bb", "cb" });

            AddProvider(builder, "a", new string[] { }, new string[] { }, new string[] { "aa", "ab" }, new string[] { "aa", "ab" },
                new string[] { }, new string[] { "aa", "ab", "ba", "bb", "cb" }, new string[] { }, new string[] { "aa", "ab", "ba", "bb", "cb" });

            Dictionary<string, object> services = Impl.InitializeGraph(graph, new Option<FastFunc<Tuple<IProviderVertex, IEnumerable<string>>, Unit>>());

            Assert.AreEqual("a", services["ab"]);
            Assert.AreEqual("b", services["ba"]);
            Assert.AreEqual("b", services["bb"]);
            Assert.AreEqual("c", services["aa"]);
            Assert.AreEqual("c", services["cb"]);
        }
    }
}
